﻿using System;
using System.Collections.Generic;
using System.Linq;

using NHibernate;
using NHibernate.Linq;

using ZQNB.Common;
using ZQNB.Common.Encrypt;
using ZQNB.Common.Events;
using ZQNB.BaseLib.Accounts.Events;
using ZQNB.Entity.Accounts;

namespace ZQNB.BaseLib.Accounts.Impl
{
    public class LocalAccountService : IAccountService
    {
        private readonly ISession _session;
        private readonly AccountPolicy _accountPolicy;
        private readonly PasswordEncryptor _passwordEncryptor;

        public LocalAccountService(ISession session, AccountPolicy accountPolicy, PasswordEncryptor passwordEncryptor)
        {
            this._session = session;
            this._accountPolicy = accountPolicy;
            this._passwordEncryptor = passwordEncryptor;
        }

        public bool Validate(string identity, string password)
        {
            var account = GetAccount(identity);
            if (account == null)
            {
                return false;
            }

            bool checkAccountPass = CheckAccountPass(account, password);
            return checkAccountPass;
        }

        public Account GetAccount(string identity)
        {
            if (string.IsNullOrWhiteSpace(identity))
            {
                return null;
            }

            var account = _session.Query<Account>().SingleOrDefault(x => x.LoginName == identity);
            if (account != null)
            {
                return account;
            }

            if (_accountPolicy.SupportEmail)
            {
                account = _session.Query<Account>().SingleOrDefault(x => x.Email == identity);
                if (account != null)
                {
                    return account;
                }
            }

            if (_accountPolicy.SupportCustomNo)
            {
                account = _session.Query<Account>().SingleOrDefault(x => x.CustomNo == identity);
                if (account != null)
                {
                    return account;
                }
            }

            return null;
        }

        public bool ResetPassword(string identity)
        {
            string defaultPassword = _accountPolicy.DefaultPassword;
            return ResetPassword(identity, defaultPassword);
        }

        public bool ResetPassword(string identity, string defaultPassword)
        {
            Account account = GetAccount(identity);
            if (account == null)
            {
                return false;
            }

            using (var t = _session.BeginTransaction())
            {
                PasswordFormat format = account.PasswordFormat;
                string salt = account.PasswordSalt;
                string encryptPass = _passwordEncryptor.Encrypt(defaultPassword, format, salt);

                account.Password = encryptPass;
                _session.Update(account);
                t.Commit();
                return true;
            }
        }

        public bool ChangePassword(string identity, string oldPassword, string newPassword)
        {
            Account account = GetAccount(identity);
            if (account == null)
            {
                return false;
            }

            bool isOk = CheckAccountPass(account, oldPassword);
            if (!isOk)
            {
                return false;
            }

            return ResetPassword(identity, newPassword);
        }

        public void LockAccount(string identity)
        {

            using (var t = _session.BeginTransaction())
            {
                Account account = GetAccount(identity);
                account.IsLocked = true;
                _session.Update(account);
                t.Commit();
            }

        }

        public void UnLockAccount(string identity)
        {
            using (var t = _session.BeginTransaction())
            {
                Account account = GetAccount(identity);
                account.IsLocked = false;
                _session.Update(account);
                t.Commit();
            }
        }

        public void NotifyLogin(string loginName)
        {
            //Account account = GetAccount(loginName);
            //account.LastLoginDate = DateTime.Now;
            //用户登录的事件通知
            var userLoginEvent = new UserLoginEvent(loginName);
            DomainEvents.Raise(userLoginEvent);
        }

        public void NotifyLogout(string loginName)
        {
            //Account account = GetAccount(loginName);
            //account.IsActived = false;
            //用户登出的事件通知
            var userLogoutEvent = new UserLogoutEvent(loginName);
            DomainEvents.Raise(userLogoutEvent);
        }

        public MessageResult Create(Account account)
        {
            MessageResult vr = ValidateNewAccount(account);
            if (!vr.Success)
            {
                return vr;
            }

            MessageResult mr = new MessageResult();

            //validate account
            using (var t = _session.BeginTransaction())
            {
                var countDomainLoginName = _session.Query<Account>().Count(x => x.LoginName == account.LoginName);
                if (countDomainLoginName > 0)
                {
                    mr.Message = string.Format("登录名{0}已经存在", account.LoginName);
                    return mr;
                }

                if (!string.IsNullOrWhiteSpace(account.Email))
                {
                    var countEmail = _session.Query<Account>().Count(x => x.Email == account.Email);
                    if (countEmail > 0)
                    {
                        mr.Message = string.Format("Email{0}已经存在", account.Email);
                        return mr;
                    }
                }

                if (!string.IsNullOrWhiteSpace(account.CustomNo))
                {
                    var countCustomNo = _session.Query<Account>().Count(x => x.CustomNo == account.CustomNo);
                    if (countCustomNo > 0)
                    {
                        mr.Message = string.Format("自定义身份ID{0}已经存在", account.CustomNo);
                        return mr;
                    }
                }

                account.PasswordFormat = _accountPolicy.PasswordFormat;
                account.PasswordSalt = _passwordEncryptor.GenerateRandomSalt();
                account.Password = _passwordEncryptor.Encrypt(account.Password, account.PasswordFormat, account.PasswordSalt);

                _session.Save(account);
                t.Commit();

                mr.Success = true;
                mr.Message = "注册成功";
                mr.Data = account.Id;
                return mr;
            }
        }

        public MessageResult Delete(string identity)
        {
            MessageResult mr = new MessageResult();
            
            using (var t = _session.BeginTransaction())
            {
                Account account = GetAccount(identity);
                _session.Delete(account);
                t.Commit();

                mr.Success = true;
                mr.Message = "删除成功";
                mr.Data = account.Id;
            }
            return mr;
        }

        public MessageResult Update(Account account)
        {
            MessageResult mr = new MessageResult();
            using (var t = _session.BeginTransaction())
            {
                Account theAccount = GetAccount(account.LoginName);

                MyModelHelper.SetProperties(theAccount, account, new string[]{"Id"});

                _session.Update(theAccount);
                t.Commit();
                mr.Success = true;
                mr.Message = "更新成功";
                mr.Data = account.Id;
            }

            mr.Message = "更新失败";
            return mr;
        }

        //===============helpers===================
        private bool CheckAccountPass(Account account, string password)
        {
            //锁定状态禁止登陆
            if (account.IsLocked)
            {
                return false;
            }

            PasswordFormat format = (PasswordFormat)account.PasswordFormat;
            string salt = account.PasswordSalt;
            string encryptPass = _passwordEncryptor.Encrypt(password, format, salt);
            return encryptPass == account.Password;
        }
        
        private MessageResult ValidateNewAccount(Account account)
        {
            MessageResult vr = new MessageResult();

            if (string.IsNullOrWhiteSpace(account.LoginName))
            {
                vr.Message = "LoginName不能为空！";
                return vr;
            }

            if (string.IsNullOrWhiteSpace(account.Password))
            {
                vr.Message = "Password不能为空！";
                return vr;
            }

            vr.Success = true;
            return vr;
        }
    }
}
